/**
 * Copyright (C) 2013 DaiKit.com - daikit4gxt module (admin@daikit.com)
 *
 *         Project home : http://code.daikit.com/daikit4gxt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.daikit.daikit4gxt.client;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import com.daikit.commons.shared.bean.AbstractDkBeanWithId;
import com.daikit.commons.shared.bean.DkBaseUser;
import com.daikit.commons.shared.exception.DkAmbiguousIdentifierException;
import com.daikit.commons.shared.exception.DkConversionException;
import com.daikit.commons.shared.exception.DkDataIntegrityException;
import com.daikit.commons.shared.exception.DkException;
import com.daikit.commons.shared.exception.DkIllegalArgumentException;
import com.daikit.commons.shared.exception.DkServerUnreachableException;
import com.daikit.commons.shared.exception.DkUnknownErrorException;
import com.daikit.commons.shared.exception.DkUnsupportedCaseException;
import com.daikit.commons.shared.exception.DkUnsupportedMethodException;
import com.daikit.commons.shared.exception.DkValidationException;
import com.daikit.commons.shared.exception.authentication.DkAuthenticationException;
import com.daikit.commons.shared.exception.authentication.DkNotEnoughPermissionException;
import com.daikit.commons.shared.exception.authentication.DkUserAlreadyAuthenticatedException;
import com.daikit.commons.shared.exception.authentication.DkUserLoggedChangedException;
import com.daikit.commons.shared.exception.authentication.DkUserNotAuthenticatedException;
import com.daikit.commons.shared.miscs.Couple;
import com.daikit.commons.shared.utils.DkObjectUtils;
import com.daikit.daikit4gxt.client.action.DkBaseAction;
import com.daikit.daikit4gxt.client.action.base.DkBaseOnServerLoggedUserChangedAction;
import com.daikit.daikit4gxt.client.log.DkLogger;
import com.daikit.daikit4gxt.client.ui.popup.DkFormDialog;
import com.daikit.daikit4gxt.client.ui.popup.DkMessageBox;
import com.daikit.daikit4gxt.client.ui.popup.DkMessageBox.AfterCloseListener;
import com.daikit.daikit4gxt.client.ui.popup.DkMessageBox.MessageType;
import com.daikit.daikit4gxt.client.ui.popup.DkOkCancelMessageBox;
import com.daikit.daikit4gxt.client.ui.popup.DkOkDetailsMessageBox;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.StatusCodeException;
import com.sencha.gxt.widget.core.client.form.TextArea;


/**
 * Base Error handler to handle actions exceptions.
 *
 * @author tcaselli
 * @version $Revision$ Last modifier: $Author$ Last commit: $Date$
 */
public class DkBaseErrorHandler
{

	protected DkLogger log = DkLogger.getLog(DkBaseErrorHandler.class);

	// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
	// METHOD CALLED FROM CALLBACK ON FAILURE METHOD
	// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

	/**
	 * Override this method to provide custom Error Management for your application. The overriding method should do its
	 * stuff and then call this super method.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 *           the risen exception
	 */
	public void handle(final DkBaseAction<?> callingAction, final Throwable exception)
	{
		// If the error is an Authentication Error it will be handled by this method
		if (exception instanceof StatusCodeException)
		{
			logError(callingAction, exception);
			handleKOStatusCode(callingAction, (StatusCodeException) exception);
		}
		if (exception instanceof DkAuthenticationException)
		{
			logError(callingAction, exception);
			handleAuthenticationError(callingAction, (DkAuthenticationException) exception);
		}
		else if (exception instanceof DkNotEnoughPermissionException)
		{
			logError(callingAction, exception);
			handleAuthenticationErrorNotEnoughPermission(callingAction, (DkNotEnoughPermissionException) exception);
		}
		else if (exception instanceof DkUserNotAuthenticatedException)
		{
			logError(callingAction, exception);
			handleAuthenticationErrorUserNotAuthenticated(callingAction, (DkUserNotAuthenticatedException) exception);
		}
		else if (exception instanceof DkUserLoggedChangedException)
		{
			logError(callingAction, exception);
			handleAuthenticationErrorUserLoggedChanged(callingAction, (DkUserLoggedChangedException) exception);
		}
		else if (exception instanceof DkUserAlreadyAuthenticatedException)
		{
			logError(callingAction, exception);
			handleAuthenticationErrorUserAlreadyAuthenticated(callingAction, (DkUserAlreadyAuthenticatedException) exception);
		}
		else if (exception instanceof DkServerUnreachableException)
		{
			logError(callingAction, exception);
			handleServerUnreachableError(callingAction, (DkServerUnreachableException) exception);
		}
		else if (exception instanceof DkUnknownErrorException)
		{
			logError(callingAction, exception);
			handleUnknownError(callingAction, (DkUnknownErrorException) exception);
		}
		else if (exception instanceof DkIllegalArgumentException)
		{
			logError(callingAction, exception);
			handleIllegalArgumentError(callingAction, (DkIllegalArgumentException) exception);
		}
		else if (exception instanceof DkAmbiguousIdentifierException)
		{
			logError(callingAction, exception);
			handleAmbiguousIdentifierException(callingAction, (DkAmbiguousIdentifierException) exception);
		}
		else if (exception instanceof DkConversionException)
		{
			logError(callingAction, exception);
			handleConversionException(callingAction, (DkConversionException) exception);
		}
		else if (exception instanceof DkDataIntegrityException)
		{
			logError(callingAction, exception);
			handleDataIntegrityException(callingAction, (DkDataIntegrityException) exception);
		}
		else if (exception instanceof DkValidationException)
		{
			logError(callingAction, exception);
			handleDataValidationException(callingAction, (DkValidationException) exception);
		}
		else if (exception instanceof DkUnsupportedMethodException)
		{
			logError(callingAction, exception);
			handleUnsupportedMethodException(callingAction, (DkUnsupportedMethodException) exception);
		}
		else if (exception instanceof DkUnsupportedCaseException)
		{
			logError(callingAction, exception);
			handleUnsupportedCaseException(callingAction, (DkUnsupportedCaseException) exception);
		}
		else
		{
			if (log.isErrorEnabled())
			{
				log.error("UNHANDLED EXCEPTION callingAction=[" + callingAction + "] ", exception);
			}
			handleUnexpectedError(callingAction, exception);
		}
	}

	protected void logError(final DkBaseAction<?> callingAction, final Throwable exception)
	{
		if (log.isErrorEnabled())
		{
			log.error("EXCEPTION callingAction=[" + callingAction + "] code=[" + exception.getMessage() + "]", exception);
		}
	}

	// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
	// ERRORS ACTIONS
	// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

	protected void handleKOStatusCode(final DkBaseAction<?> callingAction, final StatusCodeException exception)
	{
		displayError(DkBaseMain.i18n().error_ko_status_code_popup_title(), DkBaseMain.i18n().error_ko_status_code_popup_message(), exception, callingAction,
				new AfterCloseListener()
				{
					@Override
					public void afterClose()
					{
						onKOStatusCodePopupClick(callingAction);
					}
				});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 *           the exception
	 */
	public void handleAuthenticationError(final DkBaseAction<?> callingAction, final DkAuthenticationException exception)
	{
		displayError(DkBaseMain.i18n().error_authentication_failure_bad_login_or_password_popup_title(), DkBaseMain.i18n()
				.error_authentication_failure_bad_login_or_password_popup_message(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onBadLoginOrPasswordPopupClick(callingAction);
			}
		});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleAuthenticationErrorNotEnoughPermission(final DkBaseAction<?> callingAction, final DkNotEnoughPermissionException exception)
	{
		displayError(DkBaseMain.i18n().error_authentication_failure_not_enough_permission_popup_title(), DkBaseMain.i18n()
				.error_authentication_failure_not_enough_permission_popup_message(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onNotEnoughPermissionPopupClick(callingAction);
			}
		});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleAuthenticationErrorUserNotAuthenticated(final DkBaseAction<?> callingAction, final DkUserNotAuthenticatedException exception)
	{
		final String message = DkBaseMain.config().isStandalone() || DkBaseMain.config().isEmbeddedReconnectionAuthorized() ? DkBaseMain.i18n()
				.error_authentication_failure_user_not_authenticated_popup_message_but_will_try_to_reconnect() : DkBaseMain.i18n()
				.error_authentication_failure_user_not_authenticated_popup_message();

		displayError(DkBaseMain.i18n().error_authentication_failure_user_not_authenticated_popup_title(), message, exception, callingAction,
				new AfterCloseListener()
				{
					@Override
					public void afterClose()
					{
						onUserNotAuthenticatedPopupClick(callingAction);
					}
				});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleAuthenticationErrorUserLoggedChanged(final DkBaseAction<?> callingAction, final DkUserLoggedChangedException exception)
	{
		final DkBaseUser userLogged = DkBaseMain.model().getUserLogged();
		final DkBaseUser previousLoggedUser = DkBaseMain.model().getPreviousUserLogged();
		if (DkObjectUtils.equalsWithNull(AbstractDkBeanWithId.getId(userLogged), exception.getNewLoggedUserId()) || userLogged == null
				&& DkObjectUtils.equalsWithNull(AbstractDkBeanWithId.getId(previousLoggedUser), exception.getNewLoggedUserId()))
		{
			// In this case the new logged user is the same than the old one.
			// We just launch the reconnection action.
			onUserLoggedChangedPopupClick(callingAction, false);
		}
		else
		{
			new DkOkCancelMessageBox(DkBaseMain.i18n().error_authentication_failure_user_logged_changed_popup_title(), DkBaseMain.i18n()
					.error_authentication_failure_user_logged_changed_popup_message(), MessageType.WARNING)
			{
				@Override
				public void processOk()
				{
					onUserLoggedChangedPopupClick(callingAction, true);
				}

				@Override
				public void processCancelOrClose()
				{
					DkBaseMain.controller().invalidateUi(false);
				}

			};
		}
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleAuthenticationErrorUserAlreadyAuthenticated(final DkBaseAction<?> callingAction, final DkUserAlreadyAuthenticatedException exception)
	{
		displayError(DkBaseMain.i18n().error_authentication_failure_user_already_authenticated_popup_title(), DkBaseMain.i18n()
				.error_authentication_failure_user_already_authenticated_popup_message(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onUserAlreadyAuthenticatedPopupClick(callingAction);
			}
		});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleServerUnreachableError(final DkBaseAction<?> callingAction, final DkServerUnreachableException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_ServerUnreachable(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onServerUnreachablePopupClick(callingAction);
			}
		});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleUnknownError(final DkBaseAction<?> callingAction, final DkUnknownErrorException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_UnknownError(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onUnknownErrorPopupClick(callingAction);
			}
		});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleIllegalArgumentError(final DkBaseAction<?> callingAction, final DkIllegalArgumentException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_IllegalArgument(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onIllegalArgumentPopupClick(callingAction);
			}
		});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleUnexpectedError(final DkBaseAction<?> callingAction, final Throwable exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_UnexpectedError(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onUnexpectedErrorPopupClick(callingAction);
			}
		});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleUnsupportedMethodException(final DkBaseAction<?> callingAction, final DkUnsupportedMethodException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_UnsupportedMethodException(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onUnsupportedMethodExceptionPopupClick(callingAction);
			}
		});
	}

	/**
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param exception
	 */
	public void handleUnsupportedCaseException(final DkBaseAction<?> callingAction, final DkUnsupportedCaseException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_UnsupportedCaseException(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onUnsupportedCaseExceptionPopupClick(callingAction);
			}
		});
	}

	/**
	 *
	 * @param callingAction
	 * @param exception
	 */
	public void handleDataValidationException(final DkBaseAction<?> callingAction, final DkValidationException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_DataValidationException(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onDataValidationExceptionPopupClick(callingAction);
			}
		});
	}

	/**
	 *
	 * @param callingAction
	 * @param exception
	 */
	public void handleDataIntegrityException(final DkBaseAction<?> callingAction, final DkDataIntegrityException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_DataIntegrityException(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onDataIntegrityExceptionPopupClick(callingAction);
			}
		});
	}

	/**
	 *
	 * @param callingAction
	 * @param exception
	 */
	public void handleConversionException(final DkBaseAction<?> callingAction, final DkConversionException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_ConversionException(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onConversionExceptionPopupClick(callingAction);
			}
		});
	}

	/**
	 *
	 * @param callingAction
	 * @param exception
	 */
	public void handleAmbiguousIdentifierException(final DkBaseAction<?> callingAction, final DkAmbiguousIdentifierException exception)
	{
		displayError(DkBaseMain.i18n().error_Title(), DkBaseMain.i18n().error_AmbiguousIdentifierException(), exception, callingAction, new AfterCloseListener()
		{
			@Override
			public void afterClose()
			{
				onAmbiguousIdentifierExceptionPopupClick(callingAction);
			}
		});
	}

	// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
	// DISPLAY ERROR METHODS
	// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

	/**
	 * Method user to display error message box for each methods in this class. Override this method to provide custom
	 * message boxes in your application for all errors.
	 *
	 * @param title
	 *           the title of the message box
	 * @param message
	 *           the message of the message box
	 * @param exception
	 *           the exception
	 * @param action
	 *           the action
	 * @param callback
	 *           the callback to be called after message box is closed
	 */
	protected void displayError(final String title, final String message, final Throwable exception, final DkBaseAction<?> action,
			final AfterCloseListener afterCloseListener)
	{
		if (exception == null)
		{
			DkMessageBox.alert(title, message, afterCloseListener);
		}
		else
		{
			new DkOkDetailsMessageBox(title, message, MessageType.ERROR)
			{
				@Override
				public void processClose()
				{
					super.processClose();
					afterCloseListener.afterClose();
				}

				@Override
				public void processOk()
				{
					afterCloseListener.afterClose();
				}

				@Override
				public void processDetails()
				{
					new ExceptionDetailsMessageBox(action, exception).show();
				};
			}.show();
		}
	}

	private static final String newLine = "\n";

	private class ExceptionDetailsMessageBox extends DkFormDialog
	{
		public ExceptionDetailsMessageBox(final DkBaseAction<?> action, final Throwable exception)
		{
			super(false, 1, DisplayableButton.CANCEL);
			setResizable(true);
			final TextArea textArea = new TextArea();
			textArea.setHeight(500);
			setWidth(1050);
			final StringBuilder stringBuilder = new StringBuilder(1000);
			stringBuilder.append("ERROR REPORT: [").append(new Date().toString()).append("]").append(newLine);
			stringBuilder.append("Page URL: ").append(Window.Location.getHref()).append(newLine).append(newLine);
			if (action != null)
			{
				stringBuilder.append("Actions chain :").append(newLine);
				DkBaseAction<?> currentAction = action;
				int count = 0; // prevent infinite loop ... we never know :P
				while (currentAction != null && count++ < 100)
				{
					if (count > 1)
					{
						stringBuilder.append(newLine).append("Called by: ");
					}
					stringBuilder.append(currentAction.getProgressMessage());
					currentAction = currentAction.getParentChainAction();
				}
				stringBuilder.append(newLine).append(newLine);
			}
			if (exception instanceof DkException)
			{
				final DkException gwtlibException = (DkException) exception;
				stringBuilder.append("Server Error Context: ").append(newLine);
				for (final Entry<String, String> entry : gwtlibException.getContext().getContextMap().entrySet())
				{
					stringBuilder.append(entry.getKey()).append(": ").append(entry.getValue()).append(newLine);
				}
				stringBuilder.append(newLine).append(newLine);
			}
			if (exception.getMessage() != null)
			{
				stringBuilder.append("Exception Message: ");
			}
			if (exception instanceof DkException)
			{
				final DkException gwtlibException = (DkException) exception;
				final Iterator<Couple<String, List<String>>> it = gwtlibException.getContext().getStackTrace().iterator();
				while (it.hasNext())
				{
					final Couple<String, List<String>> couple = it.next();
					stringBuilder.append(couple.first).append(newLine);
					for (final String stackTraceElement : couple.second)
					{
						stringBuilder.append(stackTraceElement).append(newLine);
					}
					if (it.hasNext())
					{
						stringBuilder.append(newLine).append("Caused by: ");
					}
				}
			}
			else
			{
				stringBuilder.append(exception.getMessage()).append(newLine);
				for (final StackTraceElement stackTraceElement : exception.getStackTrace())
				{
					stringBuilder.append(stackTraceElement).append(newLine);
				}
				if (exception.getCause() != null && !DkObjectUtils.equalsWithNull(exception.getMessage(), exception.getCause().getMessage()))
				{
					stringBuilder.append(newLine).append("Caused by: ").append(exception.getCause().getMessage()).append(newLine);
					for (final StackTraceElement stackTraceElement : exception.getCause().getStackTrace())
					{
						stringBuilder.append(stackTraceElement).append(newLine);
					}
				}
			}
			stringBuilder.append(newLine);
			textArea.setValue(stringBuilder.toString());
			addField(textArea);
		}

		@Override
		protected String getLabelPopupTitle()
		{
			return DkBaseMain.i18n().error_details_Title();
		}

		@Override
		protected String getCancelButtonLabel()
		{
			return DkBaseMain.i18n().label_close();
		}
	}

	/**
	 * Wrapper to {@link #displayError(String, String, AfterCloseListener)} with Null Listener.
	 *
	 * @param title
	 *           the title of the message box
	 * @param message
	 *           the message of the message box
	 */
	protected void displayError(final String title, final String message)
	{
		displayError(title, message, null, null, null);
	}

	// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
	// ERRORS CALLBACKS
	// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleKOStatusCode(DkBaseAction, StatusCodeException)} . Override this method to provide custom behavior.
	 * Default is invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onKOStatusCodePopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleAuthenticationError(DkBaseAction, DkAuthenticationException)} . Override this method to provide
	 * custom behavior. Default is invalidating UI and if application is stand-alone, displays connection message box.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onBadLoginOrPasswordPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
		if (DkBaseMain.config().isStandalone())
		{
			DkBaseMain.controller().getConnectionPopupInstance().show(callingAction);
		}
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleAuthenticationErrorUserNotAuthenticated(DkBaseAction)} . Override this method to provide custom
	 * behavior. Default is invalidating UI and if application is stand-alone, displays connection message box.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onUserNotAuthenticatedPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.model().setUserLogged(null);
		DkBaseMain.controller().invalidateUi(false);
		if (DkBaseMain.config().isStandalone())
		{
			DkBaseMain.controller().getConnectionPopupInstance().show(callingAction);
		}
	}

	/**
	 * Method called by the YES button callback of the message box displayed by
	 * {@link #handleAuthenticationErrorUserLoggedChanged(DkBaseAction)} . Override this method to provide custom
	 * behavior. Default is invalidating UI and if application is stand-alone, call {@link DkBaseAction#execute()} on
	 * {@link DkBaseOnServerLoggedUserChangedAction#get()}. If another button than YES is pressed, just an UI
	 * invalidation occurs.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 * @param userReallyChanged
	 *           is true if the new logged user is really different from the old one and it is just an error risen
	 *           because of a reconnection. False if the previous logged user is really different from the new one.
	 */
	protected void onUserLoggedChangedPopupClick(final DkBaseAction<?> callingAction, final boolean userReallyChanged)
	{
		DkBaseMain.controller().invalidateUi(false);
		if (!DkBaseMain.config().isStandalone() || DkBaseMain.config().isEmbeddedReconnectionAuthorized())
		{
			// BaseAction<?> actionOnUserNotAuthenticated = BaseOnUserNotAuthenticatedAction.get() ;
			// actionOnUserNotAuthenticated.setLastChainAction(BaseOnServerLoggedUserChangedAction.get()) ;
			// actionOnUserNotAuthenticated.execute() ;
			DkBaseOnServerLoggedUserChangedAction.get(userReallyChanged ? null : callingAction).execute();
		}
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleAuthenticationErrorNotEnoughPermission(DkBaseAction)} . Override this method to provide custom
	 * behavior. Default is just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onNotEnoughPermissionPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleAuthenticationErrorUserAlreadyAuthenticated(DkBaseAction)} . Override this method to provide custom
	 * behavior. Default is just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onUserAlreadyAuthenticatedPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleAuthenticationErrorHackingAttempt(DkBaseAction)} . Override this method to provide custom behavior.
	 * Default is just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onHackingAttemptPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleServerUnreachableError(DkBaseAction)} . Override this method to provide custom behavior. Default is
	 * just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onServerUnreachablePopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleUnknownError(DkBaseAction)}. Override this method to provide custom behavior. Default is just
	 * invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onUnknownErrorPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleBadParametersError(DkBaseAction)}. Override this method to provide custom behavior. Default is just
	 * invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onIllegalArgumentPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleUnexpectedError(DkBaseAction)}. Override this method to provide custom behavior. Default is just
	 * invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onUnexpectedErrorPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleUnsupportedMethodException(DkBaseAction)}. Override this method to provide custom behavior. Default
	 * is just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onUnsupportedMethodExceptionPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleUnsupportedCaseException(DkBaseAction)}. Override this method to provide custom behavior. Default is
	 * just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onUnsupportedCaseExceptionPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleDataValidationException(DkBaseAction)}. Override this method to provide custom behavior. Default is
	 * just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onDataValidationExceptionPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleDataIntegrityException(DkBaseAction)}. Override this method to provide custom behavior. Default is
	 * just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onDataIntegrityExceptionPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleConversionException(DkBaseAction)}. Override this method to provide custom behavior. Default is just
	 * invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onConversionExceptionPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

	/**
	 * Method called by the OK or close button callback of the message box displayed by
	 * {@link #handleAmbiguousIdentifierException(DkBaseAction)}. Override this method to provide custom behavior.
	 * Default is just invalidating UI.
	 *
	 * @param callingAction
	 *           the action in which the error was risen.
	 */
	protected void onAmbiguousIdentifierExceptionPopupClick(final DkBaseAction<?> callingAction)
	{
		DkBaseMain.controller().invalidateUi(false);
	}

}
